﻿using System;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Media;


namespace FFmpegVideoClip.Lib.Controls
{
    internal class TimeLineTickBar : TickBar
    {
        private static readonly FontFamily m_Fonts = SystemFonts.MessageFontFamily;
        private static FontFamily defaultFonts => m_Fonts;
        public TimeLineTickBar() : base() { Loaded += TimeLineTickBar_Loaded; Unloaded += TimeLineTickBar_Unloaded; }
        private void OnMaxTimeChange(object? sender, EventArgs e) => MaxTime = sender == null ? TimeSpan.Zero : ((TimeLineSlider)sender).MaxTime;
        private void OnMinimumChange(object? sender, EventArgs e) => Minimum = sender == null ? 0 : ((TimeLineSlider)sender).Minimum;
        private void OnMaximumChange(object? sender, EventArgs e) => Maximum = sender == null ? 0 : ((TimeLineSlider)sender).Maximum;
        private void OnTicksChange(object? sender, EventArgs e) => Ticks = sender == null ? new DoubleCollection(0) : ((TimeLineSlider)sender).TimeRangeEdges;
        private DependencyPropertyDescriptor? MaxTimeDescriptor, CurrentMinimumDescriptor, CurrentMaximumDescriptor, TimeRangeEdgesDescriptor;
        private void TimeLineTickBar_Loaded(object sender, RoutedEventArgs e)
        {
            if (!Tools.GetParent(this, out TimeLineSlider? timeLineSlider))
                throw new InitializationException($"类型[{GetType().FullName}]的实例所在的父级中不存在[{typeof(TimeLineSlider).FullName}]");

            MaxTimeDescriptor = DependencyPropertyDescriptor.FromProperty(TimeLineSlider.MaxTimeProperty, typeof(TimeLineSlider));
            MaxTimeDescriptor.AddValueChanged(timeLineSlider, OnMaxTimeChange);

            CurrentMinimumDescriptor = DependencyPropertyDescriptor.FromProperty(TimeLineSlider.MinimumProperty, typeof(TimeLineSlider));
            CurrentMinimumDescriptor.AddValueChanged(timeLineSlider, OnMinimumChange);

            CurrentMaximumDescriptor = DependencyPropertyDescriptor.FromProperty(TimeLineSlider.MaximumProperty, typeof(TimeLineSlider));
            CurrentMaximumDescriptor.AddValueChanged(timeLineSlider, OnMaximumChange);

            TimeRangeEdgesDescriptor = DependencyPropertyDescriptor.FromProperty(TimeLineSlider.TimeRangeEdgesProperty, typeof(TimeLineSlider));
            TimeRangeEdgesDescriptor.AddValueChanged(timeLineSlider, OnTicksChange);
        }
        private void TimeLineTickBar_Unloaded(object sender, RoutedEventArgs e)
        {
            MaxTimeDescriptor?.RemoveValueChanged(this, OnMaxTimeChange);
            MaxTimeDescriptor = null;

            CurrentMinimumDescriptor?.RemoveValueChanged(this, OnMinimumChange);
            CurrentMinimumDescriptor = null;

            CurrentMaximumDescriptor?.RemoveValueChanged(this, OnMaximumChange);
            CurrentMaximumDescriptor = null;

            TimeRangeEdgesDescriptor?.RemoveValueChanged(this, OnTicksChange);
            TimeRangeEdgesDescriptor = null;
        }
        [Bindable(true)] public FontFamily UseFontFamily { get => (FontFamily)GetValue(UseFontFamilyProperty); set => SetValue(UseFontFamilyProperty, value); }
        public static readonly DependencyProperty UseFontFamilyProperty = DependencyProperty.Register(nameof(UseFontFamily), typeof(FontFamily), typeof(TimeLineTickBar), new PropertyMetadata(defaultFonts));

        [Bindable(true)] public double FontSize { get => (double)GetValue(FontSizeProperty); set => SetValue(FontSizeProperty, value); }
        public static readonly DependencyProperty FontSizeProperty = DependencyProperty.Register(nameof(FontSize), typeof(double), typeof(TimeLineTickBar), new PropertyMetadata(9d));

        [Bindable(true)] public Brush FontColor { get => (Brush)GetValue(FontColosProperty); set => SetValue(FontColosProperty, value); }
        public static readonly DependencyProperty FontColosProperty = DependencyProperty.Register(nameof(FontColor), typeof(Brush), typeof(TimeLineTickBar), new PropertyMetadata(Brushes.Black));

        [Bindable(true)] public double FontPosY { get => (double)GetValue(FontPosYProperty); set => SetValue(FontPosYProperty, value); }
        public static readonly DependencyProperty FontPosYProperty = DependencyProperty.Register(nameof(FontPosY), typeof(double), typeof(TimeLineTickBar), new PropertyMetadata(0d));

        [Bindable(true)] public double FontPosXOffset { get => (double)GetValue(FontPosXOffsetProperty); set => SetValue(FontPosXOffsetProperty, value); }
        public static readonly DependencyProperty FontPosXOffsetProperty = DependencyProperty.Register(nameof(FontPosXOffset), typeof(double), typeof(TimeLineTickBar), new PropertyMetadata(0d));

        [Bindable(true)] public TimeSpan MaxTime { get => (TimeSpan)GetValue(MaxTimeProperty); set => SetValue(MaxTimeProperty, value); }
        public static readonly DependencyProperty MaxTimeProperty = DependencyProperty.Register(nameof(MaxTime), typeof(TimeSpan), typeof(TimeLineTickBar), new PropertyMetadata(TimeSpan.Zero));

        protected override void OnRender(DrawingContext dc)
        {
            if (Ticks == null || Ticks.Count < 2)
                return;
            double max = Ticks.Max();
            double min = Ticks.Min();
            double maxtime = MaxTime.TotalMilliseconds - 1;
            if (maxtime < 1)
                return;
            double interval = this.ActualWidth / (Maximum - Minimum);
            double pos;

            if (max < maxtime && (Maximum >= maxtime || max <= Maximum))
            {
                pos = (max - Minimum) * interval;
                dc.DrawText(new FormattedText(Tools.GetTimeSpanToString_HoursMinutesSecondsDigit(TimeSpan.FromMilliseconds(max)), CultureInfo.CurrentCulture, this.FlowDirection,
                    new Typeface(UseFontFamily.ToString()), FontSize, FontColor, VisualTreeHelper.GetDpi(this).PixelsPerDip), new Point(pos - FontPosXOffset, FontPosY));
                dc.DrawLine(new Pen(this.Fill, 1), new Point(pos, 0), new Point(pos, this.ActualHeight));
            }

            if (min > 0 && (Minimum <= 0 || min >= Minimum))
            {
                pos = (min - Minimum) * interval;
                dc.DrawText(new FormattedText(Tools.GetTimeSpanToString_HoursMinutesSecondsDigit(TimeSpan.FromMilliseconds(min)), CultureInfo.CurrentCulture, this.FlowDirection,
                    new Typeface(UseFontFamily.ToString()), FontSize, FontColor, VisualTreeHelper.GetDpi(this).PixelsPerDip), new Point(pos + 6, FontPosY));
                dc.DrawLine(new Pen(this.Fill, 1), new Point(pos, 0), new Point(pos, this.ActualHeight));
            }
        }


        [Serializable]
        public class InitializationException : Exception
        {
            public InitializationException() { }
            public InitializationException(string message) : base(message) { }
            public InitializationException(string message, Exception inner) : base(message, inner) { }
            [Obsolete] protected InitializationException(
              System.Runtime.Serialization.SerializationInfo info,
              System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
        }
    }
}
